﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;

namespace FastAccess
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    };

    class Win32
    {
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // Large icon
        public const uint SHGFI_SMALLICON = 0x1; // Small icon
        
        #region Windows API

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath,
                                    uint dwFileAttributes,
                                    ref SHFILEINFO psfi,
                                    uint cbSizeFileInfo,
                                    uint uFlags);

        [DllImport("shell32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
        public static extern int PickIconDlg(IntPtr hwndOwner,
            StringBuilder lpstrFile,
            int nMaxFile,
            ref int lpdwIconIndex);

        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
        public static extern uint ExtractIconEx(string szFileName,
            int nIconIndex,
            IntPtr[] phiconLarge,
            IntPtr[] phiconSmall,
            uint nIcons);
        
        #endregion

        private static Icon GetAssociatedIcon(string url, uint size)
        {

            IntPtr hImgSmall;    //the handle to the system image list
            //IntPtr hImgLarge;    //the handle to the system image list
            string fName = url;        // 'the file name to get icon from
            SHFILEINFO shinfo = new SHFILEINFO();
            try
            {
                //Use this to get the small Icon
                hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo,
                                               (uint)Marshal.SizeOf(shinfo),
                                                Win32.SHGFI_ICON |
                                                size);

                //Use this to get the large Icon
                //hImgLarge = SHGetFileInfo(fName, 0,
                //ref shinfo, (uint)Marshal.SizeOf(shinfo),
                //Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);

                //The icon is returned in the hIcon member of the shinfo struct
                return Icon.FromHandle(shinfo.hIcon);
            }
            catch
            {
                return null;
            }
        }

        public static Icon GetAssociatedIcon16(string url)
        {
            return GetAssociatedIcon(url, SHGFI_SMALLICON);
        }

        public static Icon GetAssociatedIcon32(string url)
        {
            return GetAssociatedIcon(url, SHGFI_LARGEICON);
        }

        public static Icon GetShell32Icon(ref int iconIndex, ref string iconFile)
        {
            IntPtr[] phiconSmall = new IntPtr[1] { IntPtr.Zero };
            IntPtr[] phiconLarge = new IntPtr[1] { IntPtr.Zero };

            if (!File.Exists(iconFile))
            {
                iconFile = GetSystemPath() + @"\shell32.dll";
                iconIndex = 0;
            }

            ExtractIconEx(iconFile, iconIndex, phiconLarge, phiconSmall, 1);

            return Icon.FromHandle(phiconSmall[0]);
        }

        public static int PickIconDlg(ref int iconIndex, ref string iconFile)
        {
            if (!File.Exists(iconFile))
            {
                iconFile = GetSystemPath() + @"\shell32.dll";
                iconIndex = 0;
            }

            StringBuilder sb = new StringBuilder(iconFile, 1024);

            if (PickIconDlg(IntPtr.Zero, sb, sb.Capacity, ref iconIndex) == 1)
            {
                iconFile = sb.ToString();
                return 1;
            }
            else
                return 0;
        }
        
        public static string GetSystemPath()
        {
            return Environment.GetFolderPath(Environment.SpecialFolder.System);
        }
    }
}
